package org.intrasearch.core;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.nio.ByteBuffer;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

public final class ArtifactId implements Comparable<ArtifactId>, Externalizable
{
    private byte[] artifactDigest;
    private static final MessageDigest instance;

    static
    {
        try
        {
            instance = MessageDigest.getInstance("MD5");
        }
        catch (NoSuchAlgorithmException e)
        {
            throw new RuntimeException(e);
        }
    }

    private ArtifactId(byte[] artifactDigest)
    {
        this.artifactDigest = artifactDigest;
    }

    public static ArtifactId generateFromBytes(byte[] bytes)
    {
        return new ArtifactId(instance.digest(bytes));
    }

    public static ArtifactId generateFromString(String s)
    {
        return generateFromBytes(s.getBytes());
    }

    @Override
    public boolean equals(Object o)
    {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        ArtifactId id = (ArtifactId) o;

        return Arrays.equals(artifactDigest, id.artifactDigest);

    }

    @Override
    public int hashCode()
    {
        return Arrays.hashCode(artifactDigest);
    }

    public int compareTo(ArtifactId o)
    {
        for (int i = 0; i < artifactDigest.length; i++)
        {
            if (artifactDigest[i] != o.artifactDigest[i])
            {
                return artifactDigest[i] - o.artifactDigest[i];
            }
        }
        return 0;
    }

    public void writeExternal(ObjectOutput out) throws IOException
    {
        out.write(artifactDigest);
    }

    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
    {
        artifactDigest = new byte[instance.getDigestLength()];
        in.read(artifactDigest);
    }

    public static ArtifactId compose(Object ... objects)
    {
        byte[] buffer = null;
        for (Object object : objects)
        {
            byte[] bytes = toByteArray(object);
            if (buffer == null)
            {
                buffer = bytes;
            }
            else
            {
                ByteBuffer byteBuffer = ByteBuffer.allocate(buffer.length + bytes.length);
                byteBuffer.put(buffer);
                byteBuffer.put(bytes);
                buffer = byteBuffer.array();
            }
        }
        return generateFromBytes(buffer);
    }

    private static byte[] toByteArray(Object object)
    {
        if (object instanceof ArtifactId)
        {
            ArtifactId id = (ArtifactId) object;
            return id.artifactDigest;
        }
        if (object instanceof String)
        {
            String s = (String) object;
            return s.getBytes();
        }
        if (object == null)
        {
            return new byte[0];
        }
        throw new IllegalArgumentException("Can't compose from " + object);
    }
}
